package com.easymin.weixin.manager.impl;

import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.easymin.weixin.common.DataGrid;
import com.easymin.weixin.common.PhoneNumberHelper;
import com.easymin.weixin.common.api.DaijiaApi;
import com.easymin.weixin.common.api.ErrandApi;
import com.easymin.weixin.common.api.FreightApi;
import com.easymin.weixin.common.api.PassengerApi;
import com.easymin.weixin.common.api.SalesApi;
import com.easymin.weixin.common.api.ZhuanApi;
import com.easymin.weixin.common.api.ZhuanXianApi;
import com.easymin.weixin.controller.v4.ResultTransport;
import com.easymin.weixin.controller.v5.utils.ResultV5;
import com.easymin.weixin.entity.Order;
import com.easymin.weixin.entity.OrderGrab;
import com.easymin.weixin.entity.OrderType;
import com.easymin.weixin.entity.WxApplication;
import com.easymin.weixin.entity.passenger.Passenger;
import com.easymin.weixin.entity.sales.Coupon;
import com.easymin.weixin.manager.ErrandManager;
import com.easymin.weixin.manager.WxBindManager;
import com.easymin.weixin.service.WxApplicationService;
import com.google.common.base.Preconditions;

@Service
public class DefaultErrandManager implements ErrandManager {

  private static final Logger logger = LoggerFactory.getLogger(DefaultErrandManager.class);

  @Autowired
  private WxBindManager wxBindManager;
  @Autowired
  private ErrandApi errandApi;
  @Autowired
  private DaijiaApi daijiaApi;
  @Autowired
  private PassengerApi passengerApi;
  @Autowired
  private SalesApi salesApi;
  @Autowired
  private FreightApi freightApi;
  @Autowired
  private ZhuanApi zhuanApi;
  @Autowired
  private ZhuanXianApi zhuanXianApi;
  @Autowired
  private WxApplicationService wxApplicationService;

  @Override
  public Map<String, Object> createOrder(String title, String content, String deliverTime, String deliverAddress,
                                         Double deliverLat, Double deliverLng, Boolean errandFixPrice, Double shouldPay, Long passengerId,
                                         String passengerPhone, String channelName, String openId, Long companyId, String companyName,
                                         String startTime, String startPhone, String endPhone, String startAddress, Double startLat, Double startLng,
                                         String orderType, Double startPrice, Double mileagePrice, Double travelTimePrice, Integer travelTime,
                                         Double mileage, String appKey) throws Exception {
    Map<String, Object> map = new HashMap<String, Object>();
    map.put("code", -1);
    map.put("msg", "创建跑腿订单失败");
    Preconditions.checkArgument(StringUtils.isNotBlank(appKey), "appKey不能为空");
    Preconditions.checkArgument(StringUtils.isNotBlank(passengerPhone), "电话号码不能为空");

    Date dtime = DateUtils.parseDate(deliverTime, "yyyy-MM-dd HH:mm");
    Date stime = null;
    if (StringUtils.isNotBlank(startTime)) {
      stime = DateUtils.parseDate(startTime, "yyyy-MM-dd HH:mm");
    }
    if (stime != null && stime.after(dtime)) {
      map.put("code", -1);
      map.put("msg", "取件时间必须在交件时间之前");
      return map;
    }

    if (new Date().after(dtime)) {
      map.put("code", -1);
      map.put("msg", "交付时间过时,请重新填写");
      return map;
    }
    if (!PhoneNumberHelper.isPhoneNumber(passengerPhone)) {
      map.put("code", -1);
      map.put("msg", "电话号码格式不正确");
      return map;
    }
    if (StringUtils.isNotBlank(startPhone) && !PhoneNumberHelper.isPhoneNumber(startPhone)) {
      map.put("code", -1);
      map.put("msg", "取件电话号码格式不正确");
      return map;
    }
    if (StringUtils.isNotBlank(endPhone) && !PhoneNumberHelper.isPhoneNumber(endPhone)) {
      map.put("code", -1);
      map.put("msg", "交付电话号码格式不正确");
      return map;
    }
    if (StringUtils.isBlank(title) || title.length() > 20) {
      map.put("code", -1);
      map.put("msg", "任务标题文本为空或长度超出20字");
      return map;
    }
    if (StringUtils.isBlank(content) || content.length() > 200) {
      map.put("code", -1);
      map.put("msg", "任务内容文本为空或长度超出200字");
      return map;
    }

    if (shouldPay == null) {
      map.put("code", -1);
      map.put("msg", "创建跑腿订单失败!请先输入价格。");
      return map;
    }
    if (shouldPay != null) {
      String format = String.format("%.2f", shouldPay);
      shouldPay = Double.valueOf(format);
    }

    if (shouldPay != null && (shouldPay > 10000 || shouldPay <= 0)) {
      map.put("code", -1);
      map.put("msg", "金额输入错误!请重新输入");
      return map;
    }

    Passenger passenger = passengerApi.findById(passengerId, appKey);
    if (null == passenger) {
      map.put("code", -2);
      map.put("msg", "乘客不存在!");
      return map;
    }
    if (passenger.getInBlackList()) {
      map.put("code", -6);
      map.put("msg", "黑名单客户不允许下单!");
      return map;
    }
    if (StringUtils.isBlank(passenger.getName())) {
      passenger.setName("先生/女士");
    }
    if (StringUtils.isNotBlank(openId)) {
      // 绑定会员信息 phone和openId一对一
      wxBindManager.bind(appKey, passengerPhone, openId, passenger.getId()); // 绑定账号
    }

    Order order = new Order();
    order.setTitle(title);
    order.setContent(content);
    order.setDeliverTime(dtime);
    order.setDeliverAddress(deliverAddress);
    order.setDeliverLat(deliverLat);
    order.setDeliverLng(deliverLng);
    order.setErrandFixPrice(true);
    order.setShouldPay(shouldPay);
    order.setChannelName(channelName);
    order.setCompanyId(companyId);
    order.setCompanyName(companyName);

    order.setStartTime(stime);
    order.setStartPhone(startPhone);
    order.setStartAddress(startAddress);
    order.setStartLat(startLat);
    order.setStartLng(startLng);
    order.setEndPhone(endPhone);
    order.setStartPrice(startPrice);
    order.setMileagePrice(mileagePrice);
    order.setTravelTimePrice(travelTimePrice);
    order.setTravelTime(travelTime);
    order.setMileage(mileage);
    if (StringUtils.isNotBlank(orderType)) {
      order.setOrderType(orderType);
    } else {
      order.setOrderType("other");
    }

    JSONObject jsonObject = errandApi.create(order, passenger, appKey);

    if (null != jsonObject && jsonObject.getIntValue("code") == 0) {
      map.put("code", 0);
      map.put("msg", "下单成功");
      JSONObject jo = jsonObject.getJSONObject("data");
      Long orderId = jo.getLong("id");
      map.put("orderId", orderId);
    }

    return map;
  }

  /**
   * 查询单个订单.
   */
  @Override
  public Order findOne(Long orderId, String appKey) throws Exception {

    Order order = errandApi.findById(orderId, appKey);

    return order;
  }

  @Override
  public Map<String, Object> findOrderV2(Long orderId, String appKey, String address) throws Exception {

    Map<String, Object> order = errandApi.findOrderV2(orderId, appKey, address);

    return order;
  }

  /**
   * 查询订单v2. status 0:新单 1:已派单 2:已接单 3:执行中 6:已完成(未评价) 4:已完成 5:已销单
   */

  @Override
  public DataGrid<Map<String, Object>> findOrderV2(Long passengerId, Integer page, Integer rows, String appKey,
                                                   String address) throws Exception {

    DataGrid<Map<String, Object>> dataGrid = new DataGrid<Map<String, Object>>();
    dataGrid = errandApi.findByStatusV2(passengerId, page, rows, appKey, address);
    return dataGrid;
  }

  @Override
  public ResultTransport findOrderV4(Long orderId, String appKey, String address) {
    return errandApi.findOrderV4(orderId, appKey, address);
  }

  @Override
  public ResultTransport queryTypeV4(Long companyId, String detailedJobType, String appKey) {
    return errandApi.queryTypeV4(companyId, detailedJobType, appKey);
  }

  @Override
  public ResultV5 queryTypeV5(Long companyId, String appKey) {
    return errandApi.queryTypeV5(companyId, appKey);
  }

  /**
   * 查询订单. status 0:新单 1:已派单 2:已接单 3:执行中 6:已完成(未评价) 4:已完成 5:已销单
   */
  @Override
  public DataGrid<Map<String, Object>> findOrder(Long passengerId, Integer page, Integer rows, String status,
                                                 String appKey) throws Exception {

    DataGrid<Map<String, Object>> dataGrid = new DataGrid<Map<String, Object>>();
    dataGrid = errandApi.findByStatus(passengerId, page, rows, status, appKey);
    return dataGrid;
  }

  /**
   * 修改订单状态(接单,拒单,销单,执行,完成).
   */
  @Override
  public String updateStatus(Long orderId, Long employId, String employName, String employPhone, Long employCompanyId,
                             String action, String operator, String cause, String appKey) {
    WxApplication wxApplication = wxApplicationService.findByAppKey(appKey);

    String result = null;
    if ("jiedan".equals(action)) {
      errandApi.updateToJiedan(orderId, employId, employName, employPhone, employCompanyId, operator, null,
              appKey);
      // 接单后推送到后台并且后台处理:(更新服务人员为忙碌状态)
      daijiaApi.pushAcceptOrder(wxApplication.getAddress(), orderId);

    } else if ("cancel".equals(action)) { // 销单
      errandApi.updateToCancel(orderId, cause, operator, appKey);
      // 调用代驾接口推送到司机端 后台处理:(更新员工的状态)
      daijiaApi.pushDriver(wxApplication.getAddress(), orderId);

    } else if ("refuse".equals(action)) { // 拒单
      errandApi.updateToRefuse(orderId, employId, cause, operator, appKey);

      // 推送到后台,后台处理:(修改服务人员状态)
      daijiaApi.pushRefuseOrder(wxApplication.getAddress(), orderId);
    } else if ("run".equals(action)) { // 执行订单

      errandApi.updateToRun(orderId, operator, appKey);

    } else if ("finish".equals(action)) { // 完成订单

      errandApi.updateToFinish(orderId, operator, appKey);

    } else if ("paidan".equals(action)) {
      errandApi.updatePaidan(orderId, employId, employName, employPhone, employCompanyId, operator, appKey);
    }

    return result;
  }

  /**
   * 提交抢单请求.
   */
  @Override
  public Map<String, Object> toGrabOrder(final Long orderId, Long employId, String employName, String employPhone,
                                         Long employCompanyId, Double distance, String appKey) {
    WxApplication wxApplication = wxApplicationService.findByAppKey(appKey);
    // 抢单的前提是订单是新单状态,并且服务人员为可抢单状态
    Map<String, Object> map = new HashMap<String, Object>();
    try {
      boolean bool = false;
      bool = daijiaApi.findEmployStatus(wxApplication.getAddress(), employId);
      if (!bool) {
        map.put("code", -1);
        map.put("msg", "司机有其它业务订单,暂时不能抢跑腿订单");
        return map;
      }

      Order order = errandApi.findById(orderId, appKey);
      if (order.getStatus() != 0) {
        map.put("code", -1);
        map.put("msg", "订单已被抢或已指派给其他服务人员");
        map.put("time", 0);
        return map;
      }

    } catch (Exception ex) {
      logger.error(ex.getMessage());
    }
    List<OrderGrab> list = errandApi.findOrderGrab(orderId, appKey);
    if (null != list && list.size() != 0) {
      for (OrderGrab o : list) {
        if (employId.equals(o.getEmployId())) {
          map.put("code", 0);
          map.put("msg", "已经提交过抢单请求");
          int num = 3
                  - (int) (new Date().getTime() - list.get(list.size() - 1).getCreated().getTime()) / 1000;
          int time = 1;
          if (num >= 0) {
            time = num;
          }
          map.put("time", time);
          return map;
        }
      }
    }
    JSONObject jsonObject = errandApi.addOrderGrab(orderId, employId, employName, employPhone, employCompanyId,
            distance, appKey);
    if (null != jsonObject && jsonObject.getIntValue("code") == 0) {
      map.put("code", 0);
      map.put("msg", "提交抢单请求成功");
    }
    int time = 3;
    if (list != null && list.size() != 0) {
      time = time - (int) (new Date().getTime() - list.get(list.size() - 1).getCreated().getTime()) / 1000;
      if (time < 0) {
        time = 1;
      }
    }
    map.put("time", time);
    return map;
  }

  /**
   * 请求中实时获取抢单人数量.
   */
  @Override
  public Map<String, Object> grabTime(Long orderId, String appKey) {
    Map<String, Object> map = new HashMap<String, Object>();
    List<OrderGrab> list = errandApi.findOrderGrab(orderId, appKey);
    Integer number = 1;
    if (list != null && list.size() != 0) {
      number = list.size();
      map.put("code", 0);
      map.put("msg", "请求成功");
      map.put("number", number);
    } else {
      map.put("code", -1);
      map.put("msg", "请求失败");
      map.put("number", 0);
    }
    return map;
  }

  @Override
  @Transactional(rollbackFor = Exception.class)
  public synchronized Map<String, Object> grab(String employName, String employPhone, Double distance,
                                               final Long orderId, final Long employId, final Long employCompanyId, Integer errandGrabAmount,
                                               final String appKey) {
    Map<String, Object> grabOrder = toGrabOrder(orderId, employId, employName, employPhone, employCompanyId,
            distance, appKey);
    if ((int) grabOrder.get("code") == 0) {
      grabOrder = grabOrder(orderId, employId, errandGrabAmount, appKey);
    }
    return grabOrder;
  }

  /**
   * 指派订单给某个服务人员.
   */
  @Override
  @Transactional(rollbackFor = Exception.class)
  public synchronized Map<String, Object> grabOrder(final Long orderId, final Long employId,
                                                    final Integer errandGrabAmount, final String appKey) {
    final Map<String, Object> map = new HashMap<String, Object>();
    final WxApplication wxApplication = wxApplicationService.findByAppKey(appKey);
    map.put("code", -1);
    map.put("msg", "抢单失败");
    Order order = null;
    try {
      order = errandApi.findById(orderId, appKey);
    } catch (Exception ex) {
      logger.error(ex.getMessage());
    }
    if (null != order && order.getStatus() == 0) {
      List<OrderGrab> list = errandApi.findOrderGrab(orderId, appKey);
      if (list != null && list.size() != 0) {
        OrderGrab grab = list.get(0);
        if (employId.equals(grab.getEmployId())) {
          try {
            boolean bool = false;
            bool = daijiaApi.findEmployStatus(wxApplication.getAddress(), employId);
            if (!bool) {
              map.put("code", -1);
              map.put("msg", "司机忙碌,暂时不能抢单");
              return map;
            }
            errandApi.updateToJiedan(orderId, grab.getEmployId(), grab.getEmployName(),
                    grab.getEmployPhone(), grab.getEmployCompanyId(), grab.getEmployName(),
                    errandGrabAmount, appKey);
            // 接单后推送到代驾项目并且处理:(更新服务人员为忙碌状态)
            daijiaApi.pushAcceptOrder(wxApplication.getAddress(), orderId);
            // 设置抢单记录对象为成功状态
            errandApi.updateOrderGrab(grab.getId(), appKey);

            map.put("code", 0);
            map.put("msg", "抢单成功");
            return map;
          } catch (Exception ex) {
            map.put("code", -1);
            map.put("msg", "抢单失败");
            logger.error(ex.getMessage());
            return map;
          }

        } else {
          map.put("code", -1);
          map.put("msg", "抢单失败");
        }
      }
    } else {
      map.put("code", -1);
      map.put("msg", "订单已被抢或已指派给其他服务人员");
    }
    return map;
  }

  /**
   * 评价订单.
   */
  @Override
  public String review(Long orderId, Double score, String content, String appKey) {

    String result = null;

    JSONObject jsonObject = errandApi.review(orderId, score, content, appKey);

    int code = jsonObject.getIntValue("code");
    if (code != 0) {
      result = "评价失败";
    }

    return result;
  }

  /**
   * 最新订单(没有派单的)status=0.
   */
  @Override
  public DataGrid<Map<String, Object>> findNewOrder(Integer page, Integer rows, String appKey) {
    DataGrid<Map<String, Object>> dataGrid = new DataGrid<Map<String, Object>>();
    dataGrid = errandApi.findNewOrder(page, rows, appKey);
    return dataGrid;
  }

  /**
   * 查询附近的新订单(status=0).
   */
  @Override
  public DataGrid<Map<String, Object>> findNearOrder(Double longitude, Double latitude, Double distance, Integer page,
                                                     Integer rows, String appKey) {
    DataGrid<Map<String, Object>> dataGrid = new DataGrid<Map<String, Object>>();
    dataGrid = errandApi.findNearOrder(longitude, latitude, distance, page, rows, appKey);
    return dataGrid;
  }

  /**
   * 司机当前任务(已接单,已执行但未完成的).
   */
  @Override
  public DataGrid<Map<String, Object>> findMyWork(Long employId, Double longitude, Double latitude, Integer page,
                                                  Integer rows, String appKey) {
    DataGrid<Map<String, Object>> dataGrid = new DataGrid<Map<String, Object>>();
    dataGrid = errandApi.findMyWork(employId, longitude, latitude, page, rows, appKey);
    return dataGrid;
  }

  /**
   * 查询三个司机端列表的订单数量.
   */
  @Override
  public Map<String, Object> queryCount(Long employId, Double longitude, Double latitude, Double distance,
                                        String appKey) {
    Map<String, Object> map = new HashMap<String, Object>();
    map = errandApi.queryCounts(employId, longitude, latitude, distance, appKey);
    return map;
  }

  /**
   * 查询统计客户端的三个列表订单数量.
   */
  @Override
  public Map<String, Object> queryOrders(Long passengerId, String appKey) {

    Map<String, Object> map = new HashMap<String, Object>();
    map = errandApi.queryOrders(passengerId, appKey);
    return map;
  }

  @Override
  public String findErrandPay(String city, String acKey, String appKey) {
    return errandApi.findPriceInfo(city, acKey, appKey);
  }

  @Override
  public String hasten(Long orderId, String appKey) {
    String hasten = errandApi.hasten(orderId, appKey);
    return hasten;
  }

  @Override
  public int saveOrderImgs(Long orderId, String channelName, String imgs, String appKey) {
    return errandApi.saveImgs(orderId, channelName, imgs, appKey);
  }

  @Override
  public List<OrderType> findByCompanyId(Long companyId, String appKey) {
    return errandApi.findByCompanyId(companyId, appKey);
  }

  @Override
  public OrderType findOrderType(Long orderTypeId, String appKey) {
    return errandApi.findOrderType(orderTypeId, appKey);
  }

  @Override
  public ResultTransport findOrderTypeV4(Long orderTypeId, String appKey) {
    return errandApi.findOrderTypeV4(orderTypeId, appKey);
  }

  @Override
  public Map<String, Object> saveWeixinOrder(Long passengerId, String passengerName, String passengerPhone,
                                             String startAddress, Double startLat, Double startLng, String deliverAddress, Double deliverLat,
                                             Double deliverLng, Double startPrice, Double mileagePrice, Double travelTimePrice, Double mileage,
                                             Integer travelTime, Double shouldPay, Long orderTypeId, String content, String appKey, String channelName,
                                             String serverAddress) {
    Map<String, Object> map = new HashMap<String, Object>();

    Passenger passenger = passengerApi.findById(passengerId, appKey);
    // 并行单量判断
    Long count = errandApi.countNotFinishedByPassenger(passengerId, appKey);
    Long number = 1L;
    if (null != passenger.getPassengerGrade() && passenger.getPassengerGrade().getParallelOrderNumber() > 0
            && count + number > passenger.getPassengerGrade().getParallelOrderNumber()) {
      map.put("code", -86);
      map.put("msg", "您当前有" + count + "个订单未结束!不能再下新单。");
      return map;
    }

    JSONObject object = daijiaApi.getServices(serverAddress);
    if (object != null) {
      Long num = 0L;
      boolean daijia = object.getBooleanValue("daijia");
      if (daijia) {
        num += daijiaApi.countNotPayAmounts(serverAddress, passengerId);
      }
      boolean zhuanche = object.getBooleanValue("zhuanche");
      if (zhuanche) {
        num += zhuanApi.countNotPayAmounts(passengerId, appKey);
      }
      boolean paotui = object.getBooleanValue("paotui");
      if (paotui) {
        num += errandApi.countNotPayAmounts(passengerId, appKey);
      }
      boolean freight = object.getBooleanValue("freight");
      if (freight) {
        num += freightApi.countNotPayAmounts(passengerId, appKey);
      }
      boolean zhuanxian = object.getBooleanValue("zhuanxian");
      if (zhuanxian) {
        num += zhuanXianApi.countNotPayAmounts(passengerId, appKey);
      }
      if (num > 0) {
        map.put("code", -54);
        map.put("msg", "还有未完成支付的订单，不能下单");
        return map;
      }
    }

    Long countRunning = errandApi.countRunning(passengerId, appKey);
    if (countRunning > 10) {
      map.put("code", -55);
      map.put("msg", "您今日下单已达到上限，继续下单请联系客服");
      return map;
    }

    Order order = new Order();
    order.setPassengerId(passengerId);
    order.setPassengerName(passengerName);
    order.setPassengerPhone(passengerPhone);
    OrderType orderType = errandApi.findOrderType(orderTypeId, appKey);
    if (orderType == null) {
      map.put("code", -4);
      map.put("message", "跑腿类型不存在");
      return map;
    }
    order.setCompanyId(orderType.getCompanyId());
    order.setCompanyName(orderType.getCompanyName());
    order.setStartAddress(startAddress);
    order.setStartLat(startLat);
    order.setStartLng(startLng);
    order.setDeliverAddress(deliverAddress);
    order.setDeliverLat(deliverLat);
    order.setDeliverLng(deliverLng);
    order.setChannelName(channelName);
    order.setStartTime(new Date());
    order.setStartPrice(startPrice);
    order.setMileagePrice(mileagePrice);
    order.setTravelTimePrice(travelTimePrice);
    order.setMileage(mileage);
    order.setTravelTime(travelTime);
    order.setShouldPay(shouldPay);
    order.setOrderTypeId(orderTypeId);
    List<Coupon> couponList = salesApi.findByPassengerId(passengerId, "paotui", appKey);
    Long couponId = null;
    if (couponList != null && couponList.size() != 0) {
      couponId = couponList.get(0).getId();
    }
    if (couponId != null) {
      Map<String, Object> coupons = salesApi.coupons(couponId, appKey);
      if ((int) coupons.get("code") == 0) {
        Coupon coupon = (Coupon) coupons.get("data");
        if (coupon != null) {
          order.setCouponId(couponId);
          if (coupon.getCouponRule().getType() == 1) {
            order.setCouponMoney(coupon.getCouponRule().getMoney().doubleValue());
          } else {
            Double dazeMoney = shouldPay * (coupon.getCouponRule().getDiscount() / 10);
            order.setCouponMoney(dazeMoney);
          }
        }
      }
    }
    order.setContent(content);
    order.setAppkey(appKey);
    order = errandApi.saveOrder(order);
    if (order.getId() != null && couponId != null) {
      salesApi.update(couponId, 2, appKey);
    }
    if (order.getId() != null && order.getId() != 0) {
      daijiaApi.pushNewOrder(serverAddress, order.getId());
      map.put("code", 0);
      map.put("message", "下单成功");
      map.put("data", order);
    }
    return map;
  }

  @Override
  public Order saveOrder(Long passengerId, String passengerName, String passengerPhone, Long companyId,
                         String companyName, String startAddress, Double startLat, Double startLng, String deliverAddress,
                         Double deliverLat, Double deliverLng, String channelName, Date startDate, Double startPrice,
                         Double mileagePrice, Double travelTimePrice, Double mileage, Integer travelTime, Double shouldPay,
                         Long orderTypeId, Long couponId, String content, String imgs, String voiceUrl, Long employId,
                         Long employCompanyId, String employName, String employPhone, String appKey, String startDetailed,
                         String endDetailed, String recipients, String phone, String weight, String buyNeeds, Double goodsCash,
                         Double thanksCash, String addServices, String tips, String matter, boolean prePay, String payType,
                         String address) {
    Order order = new Order();
    order.setPassengerId(passengerId);
    order.setPassengerName(passengerName);
    order.setPassengerPhone(passengerPhone);
    order.setCompanyId(companyId);
    order.setCompanyName(companyName);
    order.setStartAddress(startAddress);
    order.setStartLat(startLat);
    order.setStartLng(startLng);
    order.setDeliverAddress(deliverAddress);
    order.setDeliverLat(deliverLat);
    order.setDeliverLng(deliverLng);
    order.setChannelName(channelName);
    order.setStartTime(startDate);
    order.setStartPrice(startPrice);
    order.setMileagePrice(mileagePrice);
    order.setTravelTimePrice(travelTimePrice);
    order.setMileage(mileage);
    order.setTravelTime(travelTime);
    order.setShouldPay(shouldPay);
    order.setOrderTypeId(orderTypeId);
    // 司机补单时的数据
    order.setEmployId(employId);
    order.setEmployName(employName);
    order.setEmployPhone(employPhone);
    order.setEmployCompanyId(employCompanyId);

    // 新增字段
    order.setStartDetailed(startDetailed);
    order.setEndDetailed(endDetailed);
    order.setRecipients(recipients);
    order.setPhone(phone);
    order.setWeight(weight);
    order.setMatter(matter);
    order.setBuyNeeds(buyNeeds);
    order.setGoodsCash(goodsCash);
    order.setThanksCash(thanksCash);
    order.setAddServices(addServices);
    order.setTips(tips);

    // 设置优惠券金额
    Double couponMoney = 0d;
    if (couponId != null) {
      Map<String, Object> coupons = salesApi.coupons(couponId, appKey);
      if ((int) coupons.get("code") == 0) {
        Coupon coupon = (Coupon) coupons.get("data");
        if (coupon != null) {
          order.setCouponId(couponId);
          if (coupon.getCouponRule().getType() == 1) {
            couponMoney = coupon.getCouponRule().getMoney().doubleValue();
            order.setCouponMoney(couponMoney);
          } else {
            couponMoney = shouldPay - (shouldPay * (coupon.getCouponRule().getDiscount() / 10));
            order.setCouponMoney(BigDecimal.valueOf(couponMoney).setScale(0, BigDecimal.ROUND_DOWN).doubleValue());
          }
        }
      }
    }

    // 如果开启了预付费 设置预付费类型
    if (prePay) {
      if (couponMoney > 0) {
        if (shouldPay - couponMoney <= 0) {
          order.setPrePayTypeDetail(Order.PayTypeDetails.coupon);
        } else {
          if (payType.equals(Order.PayTypeDetails.sign.toString())) {
            order.setPrePayTypeDetail(Order.PayTypeDetails.coupon_sign);
          } else if (payType.equals(Order.PayTypeDetails.balance.toString())) {
            order.setPrePayTypeDetail(Order.PayTypeDetails.coupon_balance);
          }
        }
      } else {
        order.setPrePayTypeDetail(Order.PayTypeDetails.valueOf(payType));
      }
    }

    order.setContent(content);
    order.setImgs(imgs);
    order.setVoice(voiceUrl);
    order.setAppkey(appKey);
    order = errandApi.saveOrder(order);

    // 预付费时 余额/签单/微信/支付宝 支付记录
    if (prePay && null != order && order.getId() != null) {
      daijiaApi.orderPay(address, order.getId());
    }

    if (null != order && order.getId() != null && couponId != null) {
      salesApi.update(couponId, 2, appKey);
    }

    return order;
  }

  @Override
  public ResultTransport saveOrderV4(Long passengerId, String passengerName, String passengerPhone, Long companyId,
                                     String companyName, String startAddress, Double startLat, Double startLng, String deliverAddress,
                                     Double deliverLat, Double deliverLng, String channelName, Double startPrice, Double mileagePrice,
                                     Double travelTimePrice, Double mileage, Integer travelTime, Double shouldPay, Long orderTypeId,
                                     Long couponId, String content, String imgs, String voiceUrl, Long employId, Long employCompanyId,
                                     String employName, String employPhone, String appKey,Double weight) {
    Order order = new Order();

    order.setPassengerId(passengerId);
    order.setPassengerName(passengerName);
    order.setPassengerPhone(passengerPhone);
    order.setCompanyId(companyId);
    order.setCompanyName(companyName);
    order.setStartAddress(startAddress);
    order.setStartLat(startLat);
    order.setStartLng(startLng);
    order.setDeliverAddress(deliverAddress);
    order.setDeliverLat(deliverLat);
    order.setDeliverLng(deliverLng);
    order.setChannelName(channelName);
    order.setStartPrice(startPrice);
    order.setMileagePrice(mileagePrice);
    order.setTravelTimePrice(travelTimePrice);
    order.setMileage(mileage);
    order.setTravelTime(travelTime);
    order.setShouldPay(shouldPay);
    order.setOrderTypeId(orderTypeId);
    // 司机补单时的数据
    order.setEmployId(employId);
    order.setEmployName(employName);
    order.setEmployPhone(employPhone);
    order.setEmployCompanyId(employCompanyId);
    // 司机补单时直接派单,接单操作
    if (couponId != null) {
      ResultTransport transport = salesApi.couponsV4(couponId, appKey);
      if (transport.getCode() == 0 && transport.getData() != null) {
        Coupon coupon = JSON.parseObject(transport.getData().toString(), Coupon.class);
        order.setCouponId(coupon.getId());
        if (coupon.getCouponRule().getType() == 1) {
          order.setCouponMoney(coupon.getCouponRule().getMoney().doubleValue());
        } else {
          Double dazeMoney = shouldPay * (coupon.getCouponRule().getDiscount() / 10);
          order.setCouponMoney(dazeMoney);
        }
      }
    }
    order.setContent(content);
    order.setImgs(imgs);
    order.setVoice(voiceUrl);
    order.setAppkey(appKey);
    order.setWeight(String.valueOf(weight));
    ResultTransport resultTransport = errandApi.saveOrderV4(order);

    if (resultTransport.getCode() == 0) {
      Long orderId = Long.valueOf(resultTransport.getData().toString());

      if (orderId != null && couponId != null) {
        salesApi.updateV4(couponId, 2, appKey);
      }
    }
    return resultTransport;
  }

  @Override
  public String reviewV2(Long orderId, Double score, String content, String appKey) {

    String result = null;

    JSONObject jsonObject = errandApi.reviewV2(orderId, score, content, appKey);

    int code = jsonObject.getIntValue("code");
    if (code != 0) {
      result = "评价失败";
    }

    return result;
  }

  @Override
  public String updateStatusV2(Long orderId, Long employId, String employName, String employPhone,
                               Long employCompanyId, String action, String operator, String cause, String appKey) {
    WxApplication wxApplication = wxApplicationService.findByAppKey(appKey);

    String result = null;
    try {
      if ("jiedan".equals(action)) {
        errandApi.updateToJiedanV2(orderId, employId, employName, employPhone, employCompanyId, operator,
                appKey);
        // 接单后推送到后台并且后台处理:(更新服务人员为忙碌状态)
        daijiaApi.pushAcceptOrder(wxApplication.getAddress(), orderId);
      } else if ("cancel".equals(action)) { // 销单
        errandApi.updateToCancenV2(orderId, cause, operator, appKey);
        // 调用代驾接口推送到司机端 后台处理:(更新员工的状态)
        daijiaApi.pushDriver(wxApplication.getAddress(), orderId);
      } else if ("refuse".equals(action)) { // 拒单
        errandApi.updateToRefuse(orderId, employId, cause, operator, appKey);
        // 推送到后台,后台处理:(修改服务人员状态)
        daijiaApi.pushRefuseErrand(wxApplication.getAddress(), orderId, employId, cause);
      } else if ("run".equals(action)) { // 执行订单
        errandApi.updateToRun(orderId, operator, appKey);
        daijiaApi.pushRunOrder(wxApplication.getAddress(), orderId);
      } else if ("finish".equals(action)) { // 完成订单
        errandApi.updateToFinish(orderId, operator, appKey);
      }
    } catch (Exception ex) {
      result = ex.getMessage();
      logger.error(ex.getMessage());
    }
    return result;
  }

  @Override
  public String hastenV2(Long orderId, String appKey) {
    String hasten = errandApi.hastenV2(orderId, appKey);
    return hasten;
  }

  @Override
  public Order findOneOrderV2(Long orderId, String appKey) {
    return errandApi.findOneOrderV2(orderId, appKey);
  }

  /**
   * 司机当前任务(已接单,已执行但未完成的).
   */
  @Override
  public DataGrid<Map<String, Object>> findMyWorkV2(Long employId, Double longitude, Double latitude, Integer page,
                                                    Integer rows, String appKey, String address) {
    DataGrid<Map<String, Object>> dataGrid = new DataGrid<Map<String, Object>>();
    dataGrid = errandApi.findMyWorkV2(employId, longitude, latitude, page, rows, appKey, address);
    return dataGrid;
  }

  @Override
  public DataGrid<Map<String, Object>> queryFinishOrderV2(Long employId, Integer page, Integer rows, String appKey) {
    DataGrid<Map<String, Object>> dataGrid = new DataGrid<Map<String, Object>>();
    dataGrid = errandApi.queryFinishOrderV2(employId, page, rows, appKey);
    return dataGrid;
  }

  /**
   * V2抢单.
   */
  @Override
  @Transactional(rollbackFor = Exception.class)
  public synchronized Map<String, Object> grabV2(String employName, String employPhone, Double distance,
                                                 final Long orderId, final Long employId, final Long employCompanyId, final String appKey) {
    Map<String, Object> grabOrder = toGrabOrder(orderId, employId, employName, employPhone, employCompanyId,
            distance, appKey);
    if ((int) grabOrder.get("code") == 0) {
      grabOrder = grabOrderV2(orderId, employId, appKey);
    }
    return grabOrder;
  }

  /**
   * 指派订单给某个服务人员.
   */
  @Override
  @Transactional(rollbackFor = Exception.class)
  public synchronized Map<String, Object> grabOrderV2(final Long orderId, final Long employId, final String appKey) {
    final Map<String, Object> map = new HashMap<String, Object>();
    final WxApplication wxApplication = wxApplicationService.findByAppKey(appKey);
    map.put("code", -1);
    map.put("msg", "抢单失败");
    Order order = null;
    try {
      order = errandApi.findById(orderId, appKey);
    } catch (Exception ex) {
      logger.error(ex.getMessage());
    }
    if (null != order && order.getStatus() == 0) {
      List<OrderGrab> list = errandApi.findOrderGrab(orderId, appKey);
      if (list != null && list.size() != 0) {
        OrderGrab grab = list.get(0);
        if (employId.equals(grab.getEmployId())) {
          try {
            boolean bool = false;
            bool = daijiaApi.findEmployStatus(wxApplication.getAddress(), employId);
            if (!bool) {
              map.put("code", -1);
              map.put("msg", "司机有其它业务订单,暂时不能抢跑腿订单");
              return map;
            }
            errandApi.grabOrder(orderId, grab.getEmployId(), grab.getEmployName(), grab.getEmployPhone(),
                    grab.getEmployCompanyId(), grab.getEmployName(), appKey);
            // 接单后推送到代驾项目并且处理:(更新服务人员为忙碌状态)
            String errandSetting = daijiaApi.findErrandSetting(wxApplication.getAddress());
            JSONObject jsonObject = JSON.parseObject(errandSetting);
            Integer errandGrabAmount = jsonObject.getInteger("errandGrabAmount");
            if (null != errandGrabAmount && errandGrabAmount != 0
                    && grab.getOrderNumber() >= errandGrabAmount) {
              map.put("code", -1);
              map.put("msg", "已达抢单最大数量,暂时不能抢跑腿订单");
              return map;
            }
            errandApi.grabOrder(orderId, grab.getEmployId(), grab.getEmployName(), grab.getEmployPhone(),
                    grab.getEmployCompanyId(), grab.getEmployName(), appKey);
            // 接单后推送到代驾项目并且处理:(更新服务人员为忙碌状态)
            daijiaApi.pushAcceptOrder(wxApplication.getAddress(), orderId);
            // 设置抢单记录对象为成功状态
            errandApi.updateOrderGrab(grab.getId(), appKey);

            map.put("code", 0);
            map.put("msg", "抢单成功");
            Map<String, Object> orderMap = errandApi.findOrderV2(orderId, appKey,
                    wxApplication.getAddress());
            map.put("data", orderMap);
            return map;
          } catch (Exception ex) {
            map.put("code", -1);
            map.put("msg", "抢单失败");
            logger.error(ex.getMessage());
            return map;
          }

        } else {
          map.put("code", -1);
          map.put("msg", "抢单失败");
        }
      }
    } else {
      map.put("code", -1);
      map.put("msg", "订单已被抢或已指派给其他服务人员");
    }
    return map;
  }

  @Override
  public ResultTransport jiedan(Long orderId, Long employId, String employName, String employPhone, Long companyId,
                                String employAccount, String employPhoto, Double employScore, String operator, String appKey,
                                String errandserviceType, String platNo) {

    return errandApi.updateToJiedanV4(orderId, employId, employName, employPhone, companyId, employAccount,
            employPhoto, employScore, operator, appKey, errandserviceType, platNo);

  }

  @Override
  public ResultTransport refuse(Long orderId, Long employId, String cause, String employName, String appKey) {

    return errandApi.refuse(orderId, employId, cause, employName, appKey);

  }

  @Override
  public ResultTransport runV4(Long orderId, String operator, String appKey) {
    return errandApi.runV4(orderId, operator, appKey);
  }

  @Override
  public ResultTransport toGrabOrderV4(Long orderId, Long employId, String employName, String employPhone,
                                       Long companyId, Double employLat, Double employLng, String appKey, String errandserviceType,
                                       String platNo) {
    return errandApi.toGrabOrderV4(orderId, employId, employName, employPhone, companyId, employLat, employLng,
            appKey, errandserviceType, platNo);
  }

  @Override
  public synchronized ResultTransport grabOrderV4(final Long orderId, final Long employId, final String serverUrl,
                                                  final String appKey) {
    ResultTransport resultTransport = new ResultTransport();
    resultTransport.setCode(-22);
    resultTransport.setMessage("差一点就抢到订单啦，请再接再厉");
    String errandSetting = daijiaApi.findErrandSetting(serverUrl);
    JSONObject jsonObject = JSON.parseObject(errandSetting);
    Integer errandGrabAmount = jsonObject.getInteger("errandGrabAmount"); // 跑腿订单最大抢单数量
    List<OrderGrab> list = errandApi.findOrderGrab(orderId, appKey);
    if (list != null && list.size() != 0) {
      OrderGrab grab = list.get(0);
      if (employId.equals(grab.getEmployId())) {
        if (null != errandGrabAmount && errandGrabAmount != 0 && grab.getOrderNumber() >= errandGrabAmount) {
          resultTransport.setCode(-85);
          resultTransport.setMessage("已达抢单最大数量,暂时不能抢跑腿订单");
        } else {
          resultTransport = errandApi.grabOrderV4(orderId, appKey);
          if (resultTransport.getCode() == 0) {
            resultTransport = errandApi.findOrderV4(orderId, appKey, serverUrl);
          }
        }
      }
    }
    return resultTransport;
  }

  @Override
  public ResultTransport cancelV4(Long orderId, String cause, String appKey) {
    return errandApi.cancelV4(orderId, cause, appKey);
  }

  @Override
  public ResultTransport updateToPlace(Long orderId, String toPlace, Double longitude, Double latitude,
                                       String appKey) {
    return errandApi.updateToPlace(orderId, toPlace, longitude, latitude, appKey);
  }

  @Override
  public Long countRunning(Long passengerId, String appKey) {
    return errandApi.countRunning(passengerId, appKey);
  }

  @Override
  public Long countNotPayAmounts(Long passengerId, String appKey) {
    return errandApi.countNotPayAmounts(passengerId, appKey);
  }

  @Override
  public Long countNotFinishedByPassenger(Long passengerId, String appKey) {
    return errandApi.countNotFinishedByPassenger(passengerId, appKey);
  }

}
